package org.rufolfheszele.andpixelbyandpixel.configuration;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.rufolfheszele.andpixelbyandpixel.MainApplication;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * This class is holding configuration data related to the levels
 *
 * @author Rudolf Heszele heszele@gmail.com
 * @version 1.0
 * @since 2012-03-08
 */
public class Levels
{
		/**
		 * The only constructor takes the XML node and reads every data into its data members
		 *
		 * @param node The XML node containing the network configuration
		 */
		public Levels(Node node)
		{
			NodeList children = node.getChildNodes();

			mNode = node;
			for(int i = 0; i < children.getLength(); ++i)
			{
				Node child = children.item(i);
				
				if(true == child.getNodeName().equals("path"))
				{	
					String[] levels = null;
					
					mPath = child.getChildNodes().item(0).getNodeValue();
					mLevels = new TreeMap<String, Levels.LevelData>();
					// Open the configuration file for every level
					try
					{
						levels = MainApplication.getMainApplication().getMainActivity().getAssets().list(mPath);
					}
					catch (IOException e)
					{
						// TODO: Implement this
					}
					// Run through every level
					for(int j = 0; j < levels.length; ++j)
					{
						LevelData levelData = new LevelData();
						DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
						DocumentBuilder db = null;
						Document levelConfig = null;
						NodeList levelChildren = null;

						try
						{
							db = dbf.newDocumentBuilder();
							
							// Try to open the config file for the level
							// TODO: Try it only if levels[j] is a directory
							levelConfig = db.parse(MainApplication.getMainApplication().getMainActivity().getResources().getAssets().open(mPath + "/" + levels[j] + "/config.xml"));
						}
						catch(ParserConfigurationException exception)
						{
							// TODO: Implement this
						}
						catch(SAXException exception)
						{
							// TODO: Implement this
						}
						catch(IOException exception)
						{
							// If we are here, the file most probably not exists, so just continue
							continue;
						}
						if(null == levelConfig || false == levelConfig.getDocumentElement().getTagName().equals("pixel-by-pixel"))
						{	
							return;
						}
						levelData.mConfigFile = levelConfig;
						// Parse the level configuration
						levelChildren = levelConfig.getDocumentElement().getChildNodes();
						for(int k = 0; k < levelChildren.getLength(); ++k)
						{
							Node levelNode = levelChildren.item(i);
							
							if(true == levelNode.getNodeName().equals("level"))
							{
								levelData.mLevel = new Level(levelNode);
								mLevels.put(levels[j], levelData);
							}
						}
					}
				}
			}
		}
		
		public boolean write()
		{
			boolean returnValue = true;
			Collection<LevelData> levels = mLevels.values();
			Iterator<LevelData> levelsIterator = levels.iterator();

			while(levelsIterator.hasNext())
			{
		        try
		        {
		            // Prepare the DOM document for writing
		            Source source = new DOMSource(levelsIterator.next().mConfigFile);
		            // Prepare the output file
		            File file = new File("config.xml");
		            Result result = new StreamResult(file);
		            // Write the DOM document to the file
		            Transformer xformer = TransformerFactory.newInstance().newTransformer();
		            
		            xformer.transform(source, result);
		        }
		        catch (TransformerConfigurationException exception)
		        {
		        	returnValue = false;
		        	break;
		        }
		        catch (TransformerException exception)
		        {
		        	returnValue = false;
		        	break;
		        }
			}
	        
	        return returnValue;
		}
		
		public String getPath()
		{
			return mPath;
		}
		
		public void setPath(String path)
		{
			String nodeContent;

			mPath = path;
			nodeContent = path;
			Configuration.updateNodeContent(mNode, "path", nodeContent, null);
		}
		
		public Level getLevel(String name)
		{
			if(true == mLevels.containsKey(name))
				return mLevels.get(name).mLevel;
			
			return null;
		}
		
		/**
		 * This method creates a new level and the xml representation for it.
		 *
		 * It is the caller's responsibility to fill up the level with correct values - only the name property is filled up
		 * The new Level object is inserted into the list of levels
		 *
		 * @param name The name of the new level
		 * @return A new empty Level object
		 */
		public Level createNewLevel(String name)
		{
			// TODO: Implement this
			return null;
		}
		
		/**
		 * This method adds a new level to the configuration.
		 *
		 * This method assumes that the level has been added since the last start of the application - e.g.: The level has been downloaded from a server -, so everything.
		 * is OK with this level. The config file and the bmp file and the thumbnails as well. The new Level object is inserted into the list of levels
		 *
		 * @param name The name of the level to be added
		 * @return The newly created Level object. It is filled up with the needed informations.
		 */
		public Level addNewLevel(String name)
		{
			// TODO: Implement this
			return null;
		}
		
		public int getNumberOfLevels()
		{
			return mLevels.size();
		}
		
		public Set<String> getLevelNames()
		{
			return mLevels.keySet();
		}

		private class LevelData
		{
			public Level mLevel			= null;
			public Document mConfigFile	= null;
		}
		
		private String mPath						= null;
		private TreeMap<String, LevelData> mLevels	= null;
		private Node mNode							= null;
}
